using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Reflection;
using WCell.Util.Variables;

namespace WCell.Core.Addons
{
	/// <summary>
	/// Static helper and container class
	/// </summary>
	public static class WCellAddonMgr
	{
		/// <summary>
		/// All configurations of existing addons.
		/// </summary>
		public static readonly IList<IConfiguration> Configurations = new List<IConfiguration>();

		/// <summary>
		/// All Assemblies of all Addons and utility libraries.
		/// </summary>
		public static readonly IList<Assembly> Assemblies = new List<Assembly>();

		/// <summary>
		/// All existing AddonContexts
		/// </summary>
		public static readonly IDictionary<string, WCellAddonContext> Contexts = new Dictionary<string, WCellAddonContext>(StringComparer.InvariantCultureIgnoreCase);

		/// <summary>
		/// All existing WCellAddons by Name
		/// </summary>
		public static readonly Dictionary<string, IWCellAddon> Addons = new Dictionary<string, IWCellAddon>(StringComparer.InvariantCultureIgnoreCase);

		/// <summary>
		/// A list of all external libraries and addons to be loaded.
		/// A description is either a simple dll filename or the filename, followed by a comma, followed by 
		/// the fully specified typename of the Plugin-Class to be activated and initialized.
		/// </summary>
		public static readonly List<WCellAddonDescriptor> Descriptors = new List<WCellAddonDescriptor>();

		public static IWCellAddon GetAddon(string shortName)
		{
			IWCellAddon addon;
			Addons.TryGetValue(shortName, out addon);
			return addon;
		}

        /// <summary>
        /// 
        /// </summary>
        /// <param name="typeName">The full typename of the WCellAddon</param>
        /// <returns></returns>
        public static WCellAddonContext GetContext(string typeName)
		{
			WCellAddonContext context;
            Contexts.TryGetValue(typeName, out context);
			return context;
		}

		public static WCellAddonContext GetContext(Type addonType)
		{
			return GetContext(addonType.FullName);	
		}

		public static WCellAddonContext GetContext<A>()
			where A : IWCellAddon
		{
			return GetContext(typeof(A).FullName);
		}

		//public static void RegisterResolveHandler()
		//{
		//    var domain = AppDomain.CurrentDomain;
		//    domain.AssemblyResolve += (sender, args) => {
		//        var fullName = AssemblyName.GetAssemblyName(args.Name);
		//        var asms = domain.GetAssemblies().Where(asm => {
		//            var asmName = asm.GetName();
		//            return asmName.Name == fullName.Name &&
		//                asmName.Version.Major == fullName.Version.Major &&
		//                asmName.Version.Major == fullName.Version.Minor;
		//        });
		//        return asms.FirstOrDefault();
		//    };
		//}

		/// <summary>
		/// Creates (and -if specified- also loads) all addons from the given descriptors
		/// </summary>
		/// <param name="autoLoad">Whether to load the Assemblies and Addons immediately</param>
		public static WCellAddonContext[] LoadAll(this IEnumerable<WCellAddonDescriptor> descriptors, bool autoLoad)
		{
			var loaders = new WCellAddonContext[descriptors.Count()];
			var i = 0;
			foreach (var descriptor in descriptors)
			{
				loaders[i++] = new WCellAddonContext(descriptor, autoLoad);
			}
			return loaders;
		}

		/// <summary>
		/// 
		/// </summary>
		public static string GetDefaultDescription(this IWCellAddon addon)
		{
			return String.Format("{0} v{1} by {2} ({3})", addon.Name, addon.GetType().Assembly.GetName().Version, addon.Author, addon.Website);
		}

		internal static void AddContext(WCellAddonContext context)
		{
			Assemblies.Add(context.Assembly);
			if (context.Addon == null)
			{
				return;
			}

			var name = context.Addon.GetType().FullName;
			if (Contexts.ContainsKey(name))
			{
				throw new InvalidProgramException(
					"Tried to register two Addons with the same TypeName: " + name);
			}
			Contexts.Add(name, context);
		}
	}
}
